package restclient;

import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Iterator;

import java.io.IOException;
import java.io.InputStream;

import org.apache.http.conn.scheme.PlainSocketFactory;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.params.HttpParams;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpProtocolParams;

import org.apache.http.client.methods.HttpGet;
import org.apache.http.HttpResponse;
import org.apache.http.HttpEntity;

import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;

/**
 *
 * @author Ilio Catallo, Eleonora Ciceri
 * @version: 1.0
 * 
 * Description: The class implements a simple REST client capable
 *              of performing HTTP GET request to a given web service
 * 
 * Date: Nov 16, 2011
 */
public class RESTClient {
    
    // Attributes
    private DefaultHttpClient httpClient;
    private InputStream responseContent;
    
    /**
     * Constructor for the class RESTClient
     */
    public RESTClient(String protocol) {
        this.httpClient = createHttpClient(protocol);
    }

    /**
     * Method that creates an HTTP client 
     * @return HTTP client
     */
    private DefaultHttpClient createHttpClient(String protocol) {

        // Define the request header parameters
        HttpParams httpParams = new BasicHttpParams();
        HttpProtocolParams.setUseExpectContinue(httpParams, false);

        // Create a connection manager
        SchemeRegistry schemeRegistry = new SchemeRegistry();
        Scheme http = new Scheme(protocol, 80, PlainSocketFactory.getSocketFactory());
        schemeRegistry.register(http);

        ThreadSafeClientConnManager connManager = new ThreadSafeClientConnManager(schemeRegistry);

        // Create the HTTP client 
        return new DefaultHttpClient(connManager, httpParams);
    }
    
    /**
     * Method that executes the web API call and retrive the response data
     * @param query
     * @return response content
     */
    public void executeQuery(LinkedHashMap<String, String> query) {
        // Variables
        String queryString = composeQueryString(query);
        HttpGet request = new HttpGet(queryString);
        
        this.responseContent = doGet(request);
    }
    
    public void executeQuery(String queryString){
        
        HttpGet request = new HttpGet(queryString);
        this.responseContent = doGet(request);
    }
    
    /**
     * Method that closes the connection toward the desidered web service
     */
    public void closeConnection() {
        httpClient.getConnectionManager().shutdown();
    }
    
    private InputStream doGet(HttpGet request){
        // Variables
        HttpResponse response;
        
        // Perform the GET request
        try{
            response = this.httpClient.execute(request);
            return extractResponseContent(response);
            
        
        } catch (IOException e){
            System.err.println("Unable to perform the GET");
        }
        
        return null; 
    }

    /**
     * Method that parses the query object and compose the query string
     * @param query
     * @return queryString
     */
    private String composeQueryString(LinkedHashMap<String, String> query) {
        // Variables
        String queryString = null;
        Iterator keyIterator = query.keySet().iterator();

        // Append the URL of the web service
        queryString = (String)query.get("URL");

        //Compose the query string
        while (keyIterator.hasNext()){
            
            String paramName = (String)keyIterator.next();
            if (!paramName.equals("URL"))
                queryString += paramName + "=" + (String)query.get(paramName) + "&";
        }
        queryString = queryString.substring(0, queryString.length()-1);
        return queryString;
    }
    
    /**
     * Method that analyzes the response and extracts its content
     * @param response
     * @return response content
     */
    private InputStream extractResponseContent(HttpResponse response){
        // Variables
        HttpEntity entity;
        InputStream responseContent;

        // Get the content of the response
        entity = response.getEntity();

        try{
            responseContent = entity.getContent();
            return responseContent;

        } catch (IOException e){
            System.err.println("Unable to retrieve the response content");
            System.err.println("STACK TRACE");
            e.printStackTrace();
        }

        return null;
    }

    public InputStream getResponseContent() {
        return responseContent;
    }
    
}
